/*
 * Copyright (C) 2004-2005, Universidade Federal de Campina Grande. All rights reserved.
 */
package org.epanetgrid.otimizacao.evaluators;

import java.io.Serializable;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

import org.epanetgrid.otimizacao.objfunctions.ObjectiveFunction;
import org.epanetgrid.otimizacao.searchspace.IndividualEvaluator;
import org.epanetgrid.otimizacao.simulation.GradienteNaoConvergeOtimizacaoException;
import org.epanetgrid.otimizacao.simulation.SimulacaoNaoConvergeException;
import org.epanetgrid.otimizacao.simulation.Simulation;
import org.epanetgrid.resultado.ResultadoSimulacao;
import org.jheuristics.Individual;


/**
 * Implementa��o Default de IndividualEvaluator. Para um indiv�duo, executa-se a simula��o deste
 * calcula as fun��es objetivo e seta no indiv�duo
 * @author Marcell Manfrin, marcell@ourgrid.org, Sep 13, 2005
 * @author Thiago Emmanuel Pereira da Cunha Silva, thiagoepdc@ourgrid.org, Sep 13, 2005
 */
public class DefaultIndividualGridEvaluator implements IndividualEvaluator, Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = -1774402815500479132L;

	private Simulation simulacao;

	private ObjectiveFunction[] objectiveFunctions;

	private Map<Object, List> simulatedIndividuals = new WeakHashMap<Object, List>();

	/**
	 *
	 * @param simulacao Respons�vel por simular os indiv�duos
	 * @param objectiveFunctions Array de fun��es que avaliar�o o resultado da simula��o
	 */
	public DefaultIndividualGridEvaluator(Simulation simulacao, ObjectiveFunction[] objectiveFunctions) {
		this.simulacao = simulacao;
		this.objectiveFunctions = objectiveFunctions;
	}

	/*
	 * (non-Javadoc)
	 * @see org.smartpumping.otimizacao.searchspace.IndividualEvaluator#evaluate(org.jheuristics.Individual)
	 */
	public Individual evaluate(Individual individual) throws GradienteNaoConvergeOtimizacaoException {

		List gens = (List) individual.getGens();

		if(simulatedIndividuals.containsKey(gens)) {
			List dataApplicationResultante = simulatedIndividuals.get(gens);
			if(dataApplicationResultante == null) {
				throw new SimulacaoNaoConvergeException(" indiv�duo n�o convergiu");
			}
			individual.setDataApplication(dataApplicationResultante);
			return individual;
		}


		try{
			Object result = simulacao.simulate(gens);


			if (!(result instanceof ResultadoSimulacao)) {
				// TODO: ERROS MSG
				throw new IllegalArgumentException();
			}
			ResultadoSimulacao resultado = (ResultadoSimulacao) result;

			List results = new LinkedList();
			for (int i = 0; i < objectiveFunctions.length; i++) {
				Object evaluation = objectiveFunctions[i].evaluate(resultado);
				if (evaluation instanceof Collection) {
					results.addAll((Collection) evaluation);
				} else {
					results.add(evaluation);
				}
			}

			individual.setDataApplication(results);

			List results2 = new LinkedList();
			for (int i = 0; i < objectiveFunctions.length; i++) {
				Object evaluation = objectiveFunctions[i].evaluate(resultado);
				if (evaluation instanceof Collection) {
					results2.addAll((Collection) evaluation);
				} else {
					results2.add(evaluation);
				}
			}

			this.simulatedIndividuals.put(individual.getGens(), results2);

			return individual;
		}catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

}
